/*
 * ========================================
 * RISC-V 最小操作系统控制台驱动
 * ========================================
 * 
 * 这个文件实现了控制台功能，包括：
 * 1. 基本的字符和字符串输出
 * 2. 清屏功能
 * 3. 光标控制
 * 4. 颜色输出
 * 5. ANSI转义序列处理
 * 
 * 控制台层的作用：
 * - 提供统一的控制台接口
 * - 处理ANSI转义序列
 * - 实现高级显示功能
 * - 为格式化层提供支持
 */

#include "../include/types.h"
#include "../include/printf.h"

// ========================================
// 函数声明
// ========================================

// UART函数声明（在uart.c中定义）
void uart_putc(char c);

// ========================================
// ANSI转义序列定义
// ========================================
//
// ANSI转义序列是控制终端显示的标准方法
// 格式：\033[参数m 或 \033[参数;参数m
//

// 基本转义序列
#define ESC "\033"           // 转义字符
#define CSI ESC "["          // 控制序列引入符

// 清屏相关
#define CLEAR_SCREEN CSI "2J"     // 清除整个屏幕
#define CLEAR_LINE CSI "K"        // 清除当前行
#define CURSOR_HOME CSI "H"       // 光标回到左上角

// 光标控制
#define CURSOR_POS CSI "%d;%dH"   // 光标定位到(x,y)

// 颜色控制
#define COLOR_RESET CSI "0m"      // 重置颜色
#define COLOR_FG CSI "3%dm"       // 前景色
#define COLOR_BG CSI "4%dm"       // 背景色

// ========================================
// 基本输出函数
// ========================================

// 输出单个字符到控制台
// 这是控制台层的基础函数，所有其他输出都基于此
void console_putc(char c)
{
    // 直接调用UART输出
    // 在更复杂的实现中，这里可能会添加缓冲、过滤等功能
    uart_putc(c);
}

// 输出字符串到控制台
// 遍历字符串中的每个字符并输出
void console_puts(const char *s)
{
    if (s == 0) {
        // 处理NULL指针
        console_puts("(null)");
        return;
    }
    
    // 逐个字符输出
    while (*s) {
        console_putc(*s);
        s++;
    }
}

// ========================================
// 清屏功能实现
// ========================================
//
// 清屏有多种实现方式：
// 1. 使用ANSI转义序列（推荐）
// 2. 输出大量换行符
// 3. 直接控制显示硬件（复杂）
//
// 我们使用ANSI转义序列，因为：
// - 简单高效
// - 标准兼容
// - 不需要知道屏幕尺寸
//

void clear_screen(void)
{
    // 方案1：尝试ANSI转义序列
    console_puts("\033[2J");  // 清除整个屏幕
    console_puts("\033[H");  // 光标回到左上角
    
    // 方案2：如果ANSI不工作，使用大量换行符作为备用
    // 输出50个换行符来"清屏"
    for (int i = 0; i < 50; i++) {
        console_putc('\n');
    }
}

// ========================================
// 光标控制功能
// ========================================

// 光标定位到指定位置
// x: 列号（从1开始）
// y: 行号（从1开始）
void goto_xy(int x, int y)
{
    // 使用ANSI转义序列定位光标
    // \033[y;xH: 光标定位到第y行第x列
    char buf[32];
    int len = 0;
    
    // 构建转义序列
    buf[len++] = '\033';
    buf[len++] = '[';
    
    // 添加行号
    if (y >= 10) {
        buf[len++] = '0' + (y / 10);
    }
    buf[len++] = '0' + (y % 10);
    
    buf[len++] = ';';
    
    // 添加列号
    if (x >= 10) {
        buf[len++] = '0' + (x / 10);
    }
    buf[len++] = '0' + (x % 10);
    
    buf[len++] = 'H';
    buf[len++] = '\0';
    
    // 输出转义序列
    console_puts(buf);
}

// 清除当前行
void clear_line(void)
{
    // 发送ANSI清除行序列
    console_puts(CLEAR_LINE);
}

// ========================================
// 颜色输出功能
// ========================================
//
// 颜色输出使用ANSI转义序列
// 格式：\033[3Xm（前景色）或\033[4Xm（背景色）
// X: 0=黑, 1=红, 2=绿, 3=黄, 4=蓝, 5=洋红, 6=青, 7=白
//

// 设置前景色
static void set_foreground_color(int color)
{
    char buf[8];
    buf[0] = '\033';
    buf[1] = '[';
    buf[2] = '3';
    buf[3] = '0' + color;
    buf[4] = 'm';
    buf[5] = '\0';
    
    console_puts(buf);
}

// 重置颜色
static void reset_color(void)
{
    console_puts(COLOR_RESET);
}

// 带颜色的格式化输出
void printf_color(int color, const char *fmt, ...)
{
    // 设置颜色
    set_foreground_color(color);
    
    // 输出格式化内容
    // 注意：这里我们简化了实现，直接调用printf
    // 在实际实现中，应该避免递归调用
    printf(fmt);
    
    // 重置颜色
    reset_color();
}

// ========================================
// 扩展功能
// ========================================

// 输出带边框的文本
void printf_boxed(const char *text)
{
    int len = 0;
    const char *p = text;
    
    // 计算文本长度
    while (*p++) len++;
    
    // 输出上边框
    console_putc('+');
    for (int i = 0; i < len + 2; i++) {
        console_putc('-');
    }
    console_putc('+');
    console_putc('\n');
    
    // 输出文本行
    console_putc('|');
    console_putc(' ');
    console_puts(text);
    console_putc(' ');
    console_putc('|');
    console_putc('\n');
    
    // 输出下边框
    console_putc('+');
    for (int i = 0; i < len + 2; i++) {
        console_putc('-');
    }
    console_putc('+');
    console_putc('\n');
}

// 输出进度条
void printf_progress(int percent)
{
    const int bar_width = 50;
    int pos = (percent * bar_width) / 100;
    
    console_putc('[');
    for (int i = 0; i < bar_width; i++) {
        if (i < pos) {
            console_putc('=');
        } else if (i == pos) {
            console_putc('>');
        } else {
            console_putc(' ');
        }
    }
    console_putc(']');
    printf(" %d%%\n", percent);
}
